package com.eobard.utils;

import cn.hutool.core.util.XmlUtil;
import org.w3c.dom.*;

import java.io.File;
import java.util.stream.IntStream;

/**
 * @Author: Eobard Gu
 * @Date: 2025-07-29
 * @Description: XML文件操作工具类
 */
public class XmlUtils {

    private XmlUtils() {
    }

    /**
     * 通用替换 XML 中的属性值或标签名
     * @param oldValue 要替换的旧值
     * @param newValue 替换的新值
     */
    public static void replaceXmlValue(File xmlFile, String oldValue, String newValue) {
        //解析文件
        Document doc = XmlUtil.readXML(xmlFile);
        if (doc == null || oldValue == null || newValue == null) {
            return;
        }
        // 1.处理标签名的替换
        boolean tagModified = replaceTagName(doc, oldValue, newValue);

        // 2.处理属性值替换
        boolean attrModified = replaceAttributeValues(doc.getDocumentElement(), oldValue, newValue);

        //3.写出文件
        if (tagModified || attrModified) {
            XmlUtil.toFile(doc, String.valueOf(xmlFile));
        }
    }

    /**
     * 替换xmlFile中所有属性值中与 oldValue 相等的内容
     * @param xmlFile  xml文件路径
     * @param oldValue xml文件中指定的属性值
     * @param newValue 变更的属性值
     * @return
     */
    public static void replaceAttributeValues(String xmlFile, String oldValue, String newValue) {
        //解析文件
        Document doc = XmlUtil.readXML(xmlFile);
        if (doc == null || oldValue == null || newValue == null) {
            return;
        }
        boolean replaced = replaceAttributeValues(doc.getDocumentElement(), oldValue, newValue);
        if (replaced) {
            XmlUtil.toFile(doc, String.valueOf(xmlFile));
        }
    }

    /**
     * 替换所有属性值中与 oldValue 相等的内容
     */
    private static boolean replaceAttributeValues(Element element, String oldValue, String newValue) {
        boolean modified = false;

        NamedNodeMap attributes = element.getAttributes();
        for (int i = 0; i < attributes.getLength(); i++) {
            Node attr = attributes.item(i);
            if (attr.getNodeValue().equals(oldValue)) {
//                System.err.println("\txml引用修改");
//                System.err.println("\t\t" + attr + "\n\t\t\t" + attr.getNodeValue() + "\t->\t" + newValue);
                attr.setNodeValue(newValue);
                modified = true;
            }
        }

        // 递归子元素
        NodeList childNodes = element.getChildNodes();
        for (int i = 0; i < childNodes.getLength(); i++) {
            Node child = childNodes.item(i);
            if (child instanceof Element) {
                replaceAttributeValues((Element) child, oldValue, newValue);
                modified = true;
            }
        }
        return modified;
    }


    /**
     * 替换所有标签与 oldTagName 相等的内容
     */
    private static boolean replaceTagName(Document doc, String oldTagName, String newTagName) {
        final boolean[] modified = {false};
        //查询全部标签
        NodeList allNodes = doc.getElementsByTagName("*");
        IntStream.range(0, allNodes.getLength()).forEach(index -> {
                    //获取当前的标签元素
                    Element el = (Element) allNodes.item(index);
                    if (el.getTagName().equals(oldTagName.trim())) {
                        //真正替换操作
                        renameElementTag(el, newTagName);
                        modified[0] = true;
                    }
                }
        );
        return modified[0];
//===============================================================================================//
//上下两种写法实现功能一致,下面是兜底的方法,如果遇到不能替换的标签,可以使用下面注释的代码功能
//        List<Element> toReplace = new ArrayList<>();
//        //根据oldTagName获取对应的节点
//        NodeList nodes = doc.getElementsByTagName(oldTagName);
//        //将所有的目标tag全部放进需要转换的集合中
//        IntStream.range(0, nodes.getLength()).forEach(index -> toReplace.add((Element) nodes.item(index)));
//        //真正替换操作
//        toReplace.forEach(item -> renameElementTag(item, newTagName));
    }

    /**
     * 替换 Element 标签名，保留属性和子节点
     */
    private static void renameElementTag(Element oldElement, String newTagName) {
        Document doc = oldElement.getOwnerDocument();
        Element newElement = doc.createElement(newTagName);

        // 拷贝属性
        NamedNodeMap attributes = oldElement.getAttributes();
        IntStream.range(0, attributes.getLength()).forEach(index -> {
            //获取每一个属性
            Attr attr = (Attr) attributes.item(index);
            //设置属性k和v
            newElement.setAttribute(attr.getName(), attr.getValue());
        });

        // 拷贝子节点
        while (oldElement.hasChildNodes()) {
            Node child = oldElement.getFirstChild();
            newElement.appendChild(child);
        }

        // 替换旧节点
        Node parent = oldElement.getParentNode();
        parent.replaceChild(newElement, oldElement);
    }


}
